package com.jason.bookworm.service.impl;

import com.jason.bookworm.dao.pojo.LoginUser;
import com.jason.bookworm.dao.pojo.User;
import com.jason.bookworm.exception.ServiceException;
import com.jason.bookworm.response.Result;
import com.jason.bookworm.response.StatusEnum;
import com.jason.bookworm.service.LoginService;
import com.jason.bookworm.service.UserService;
import com.jason.bookworm.utils.JwtUtil;
import com.jason.bookworm.utils.LoginUserUtil;
import com.jason.bookworm.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private UserService userService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * @param user 用户名和密码
     * @return jwt和用户信息
     */
    @Override
    public Result<Object> login(User user) {
        //通过AuthenticationManager authenticate进行认证
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(token);
        //如果认证未通过
        if (Objects.isNull(authenticate)) {
            //抛出登录失败异常
            throw new ServiceException(StatusEnum.Login_ERR);
        }
        //认证通过，使用username生成jwt,返回到前端
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String username = loginUser.getUsername();//获取用户名
        User userInfo = loginUser.getUser();//获取用户对象
        String jwt = jwtUtil.createToken(loginUser);//生成jwt
        //将token和UserDetails对象存入redis
        redisCache.setCacheObject("Token_" + username, jwt);
        redisCache.setCacheObject("UserInfo_" + username, userInfo);
        //返回给前端的内容
        Map<String, Object> map = new HashMap<>();
        map.put("token", jwt);
        map.put("userInfo", userInfo);
        return new Result<>(StatusEnum.Login_OK, map);
    }

    /**
     * 退出登录
     *
     * @return null
     */
    @Override
    public Result<Object> logout() {
        //获取SecurityContextHolder的用户名
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        String username = loginUser.getUsername();
        //删除redis中的值
        redisCache.deleteObject("UserInfo_" + username);
        return new Result<>(StatusEnum.Logout_OK);
    }

    /**
     * @param token 令牌
     * @return 是否登录
     */
    @Override
    public Result<Object> isLogin(String token) {
        //从token中获取用户名
        String username = jwtUtil.getUsernameFromToken(token);
        //根据用户名从redis中查找对象
        User user = redisCache.getCacheObject("UserInfo_" + username);
        if (user == null) {
            return new Result<>(StatusEnum.Not_Login);
        }
        return new Result<>(StatusEnum.Login_OK);
    }

    /**
     * @param user 用户名和密码
     * @return 是否注册成功
     */
    @Override
    public Result<Object> register(User user) {
        //对密码进行加密
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        userService.registerReader(user);
        return Result.getResult(StatusEnum.Register_OK);
    }

    /**
     * @param user 用户信息
     * @return 是否修改成功
     */
    @Override
    public Result<Object> updateUserInfo(User user) {
        User loginUserInfo = LoginUserUtil.getLoginUserInfo();
        //覆盖用户关键信息
        user.setUsername(loginUserInfo.getUsername());
        user.setPrivilege(loginUserInfo.getPrivilege());
        user.setPassword(loginUserInfo.getPassword());
        user.setStatus(loginUserInfo.getStatus());
        //更新Redis
        redisCache.setCacheObject("UserInfo_" + user.getUsername(), user);
        //更新数据库
        userService.updateUser(user);
        return Result.getResult(StatusEnum.PUT_OK);
    }
}
